class Pleito < ActiveRecord::Base
  include Formulario

  attr_accessor :responsavel_id

  # Associations
  belongs_to :user,      :readonly => true
  belongs_to :incentivo, :readonly => true

  delegate :mnemonic,     :to => :incentivo
  delegate :tipo_projeto, :to => :caracterizacao

  with_options :dependent => :destroy do |p|
    p.has_one    :caracterizacao
    p.has_one    :empreendimento
    p.has_one    :analise
    p.has_many   :documentos_apresentados do
      def entregues
        find(:all, :conditions => {:entregue => true})
      end
    end
    p.has_many   :tramitacoes, :order => :created_at do
      def certificacao
        find(:last, :conditions => {:status => "recomendando"})
      end
      def recomendacao
        find(:last, :conditions => {:status => "deliberando"})
      end
      def deliberacao
        find(:last, :conditions => {:status => ["aprovado", "arquivado"]})
      end
    end
  end

  # Validations
  validates_presence_of :user, :incentivo, :codigo, :on => :create
  validates_presence_of :numero_protocolo, :data_protocolo, :on => :update

  # Callbacks
  attr_readonly :user_id, :codigo, :incentivo_id
  before_validation_on_create :generate_code

  # Helpers

  # código único identificador do pleito
  def generate_code
    require 'random_util'
    self.codigo = RandomUtil::alternate_random_string
    generate_code if Pleito.find_by_codigo(codigo, :select => :codigo)
  end

  def caracterizado?
    !caracterizacao.nil?
  end

  def reducao_fixa?
    mnemonic == "red_75_irpj"
  end

  def reducao_escalonada?
    mnemonic == "red_12_5_irpj"
  end

  def reducao?
    reducao_fixa? || reducao_escalonada?
  end

  def reinvestimento?
    mnemonic == "reinvestimento_30_irpj"
  end

  def isencao?
    mnemonic == "isencao_afrmm_iof"
  end

  def depreciacao?
    mnemonic == "depreciacao_acelerada"
  end

  def isencao_ou_depreciacao?
    isencao? || depreciacao?
  end

  def tipo
    if reducao?
      :reducao
    elsif reinvestimento?
      :reinvestimento
    elsif isencao?
      :isencao
    elsif depreciacao?
      :depreciacao
    end
  end

  def tipo_projeto_descricao
    TipoProjeto.descricao(mnemonic, tipo_projeto) if caracterizado?
  end

  def documentos
    docs = incentivo.documentos
    (caracterizado? && reducao_fixa?) ? docs + caracterizacao.documentos : docs
  end

  def certificacao
    detalhes_tramitacao(:certificacao)
  end

  def recomendacao
    detalhes_tramitacao(:recomendacao)
  end

  def deliberacao
    detalhes_tramitacao(:deliberacao)
  end

  def detalhes_tramitacao(tramitacao)
    t = tramitacoes.send(tramitacao)
    return unless t
    u = t.user
    OpenStruct.new({:texto => t.complemento1, :data => t.created_at,
                    :nome => u.name, :cargo => u.funcao,
                    :siape => u.matricula_siape, :cpf => u.cpf})
  end

  def numero_laudo_formatado
    "%04d" % (numero_laudo || 0) + "/" + (data_laudo || Time.now).year.to_s
  end

  def numero_processo_formatado
    formatar numero_processo
  end

  def numero_protocolo_formatado
    formatar numero_protocolo
  end

  def oficio(tipo, fase = nil)
    tipo = "#{tipo}_#{fase}" if fase
    oficio_data = send("data_oficio_#{tipo}") || Date.today
    OpenStruct.new({:numero => "%04d/#{oficio_data.year}" % send("numero_oficio_#{tipo}"), :data => I18n.localize(oficio_data, :format => :long)})
  end

  def portaria
    OpenStruct.new({:numero => "%04d/#{(data_portaria || Date.today).year}" % numero_portaria, :data => I18n.localize((data_portaria || Date.today), :format => :long)})
  end

  def responsavel
    r = empreendimento.componentes_empreendimento.first(:conditions => {:id => @responsavel_id}) unless @responsavel_id.blank?
    r ||= user
  end

  # Workflow

  def iniciar_inscricao(user)
    Pleito.transaction do
      self.user = user
      save!
      Empreendimento.create!(:pleito => self)
    end
  rescue Exception => ex
    logger.warn ex.message
    false
  end

  def registrar_protocolo(user, numero, data)
    self.numero_protocolo, self.data_protocolo = numero, data
    transaction do
      if inscrevendo? && valid? && protocolar
        setup_documentos_apresentados
        log_tramitacao(user)
      end
      save
    end
  end

  def setup_documentos_apresentados
    documentos.each { |d| documentos_apresentados.create(:documento => d) } if documentos_apresentados.empty?
  end

  def aceitar_inscricao(user, numero_processo, data_processo, codigo_arquivo, observacao)
    log_tramitacao(user, observacao) if registrar_processo(numero_processo, codigo_arquivo, data_processo)
  end

  # confirma a inscrição do pleito dando início a um processo
  def registrar_processo(numero_processo, codigo_arquivo, data_processo)
    return if documentos_apresentados.entregues.any?{|d| d.validade? && d.vencido? }
    self.attributes = {:numero_processo => numero_processo, :codigo_arquivo => codigo_arquivo, :data_processo => data_processo}
    triar!(:distribuindo)
  end

  def rejeitar_inscricao(user, motivo = nil, formalizacao = nil)
    log_tramitacao(user, motivo, formalizacao) if triar!(:rejeitado)
  end

  def registrar_analistas(user, analista_1_id, analista_2_id = nil)
    unless analise
      build_analise
      analise.build_vistoria
    end
    analise.analista_1_id = analista_1_id
    analise.analista_2_id = analista_2_id
    if analise.save!
      log_tramitacao(user) if distribuindo? && distribuir!
    end
  end

  def encaminhar_para_certificacao(user, texto)
    log_tramitacao(user, texto) if fechar_analise!
  end

  def encaminhar_para_recomendacao(user, texto)
    log_tramitacao(user, texto) if certificar!
  end

  def encaminhar_para_deliberacao(user, texto)
    log_tramitacao(user, texto) if recomendar!
  end

  def aprovar(user, texto, data, numero)
    if incentivo.mnemonic == "red_75_irpj" or incentivo.mnemonic == "red_12_5_irpj"
      self.attributes = {:data_laudo => data, :numero_laudo => numero.to_i}
    else
      self.attributes = {:data_portaria => data, :numero_portaria => numero.to_i}
    end
    log_tramitacao(user, texto) if deliberar!
  end

  def arquivar(user, texto)
    log_tramitacao(user, texto) if fazer_arquivamento!
  end

  def voltar_para_analise(user, texto)
    log_tramitacao(user, texto) if revisar!
  end

  def modificar_data_portaria(data, numero)
    update_attributes({:data_portaria => data, :numero_portaria => numero.to_i})
  end

  def modificar_data_laudo(data, numero)
    update_attributes({:data_laudo => data, :numero_laudo => numero.to_i})
  end

  def modificar_data_oficio_empresa(data, numero)
    update_attributes({:data_oficio_empresa => data, :numero_oficio_empresa => numero.to_i})
  end

  def modificar_data_oficio_empresa_liberacao(data, numero)
    update_attributes({:data_oficio_empresa_liberacao => data, :numero_oficio_empresa_liberacao => numero.to_i})
  end

  def modificar_data_oficio_receita(data, numero)
    update_attributes({:data_oficio_receita => data, :numero_oficio_receita => numero.to_i})
  end

  def modificar_data_oficio_bnb(data, numero)
    update_attributes({:data_oficio_bnb => data, :numero_oficio_bnb => numero.to_i})
  end

  def modificar_data_oficio_marinha(data, numero)
    update_attributes({:data_oficio_marinha => data, :numero_oficio_marinha => numero.to_i})
  end

  def log_tramitacao(user, complemento1 = nil, complemento2 = nil, complemento3 = nil)
    tramitacoes << Tramitacao.new(:complemento1 => complemento1, :complemento2 => complemento2,
                                  :complemento3 => complemento3, :user => user, :status => status)
  end

  def aasm_event_failed(event_name)
    errors.add_to_base "Falha na atualização do status. Evento: #{event_name}"
  end

  # State Machine
  include AASM
  aasm_column :status
  aasm_initial_state :inscrevendo

  aasm_state :inscrevendo,  :description => "Pré-Inscrição"
  aasm_state :triando,      :description => "Triagem"
  aasm_state :distribuindo, :description => "Distribuição"
  aasm_state :analisando,   :description => "Análise"
  aasm_state :certificando, :description => "Certificação"
  aasm_state :recomendando, :description => "Recomendação"
  aasm_state :deliberando,  :description => "Deliberação"
  aasm_state :rejeitado,    :description => "Rejeitado"
  aasm_state :aprovado,     :description => "Aprovado"
  aasm_state :arquivado,    :description => "Arquivado"

  aasm_event :protocolar do
    transitions :from => :inscrevendo, :to => :triando, :guard => :caracterizado?
  end

  aasm_event :triar do
    transitions :from => :triando, :to => [:distribuindo, :rejeitado]
  end

  aasm_event :distribuir do
    transitions :from => :distribuindo, :to => :analisando
  end

  aasm_event :fechar_analise do
    transitions :from => :analisando, :to => :certificando
  end

  aasm_event :certificar do
    transitions :from => :certificando, :to => :recomendando
  end

  aasm_event :recomendar do
    transitions :from => :recomendando, :to => :deliberando
  end

  aasm_event :deliberar do
    transitions :from => :deliberando, :to => :aprovado
  end

  aasm_event :fazer_arquivamento do
    transitions :from => [:analisando, :certificando, :recomendando, :deliberando], :to => :arquivado
  end

  aasm_event :revisar do
    transitions :from => [:certificando, :recomendando, :deliberando], :to => :analisando
  end

  private

  def formatar(numero)
    "#{numero[0,5]}.#{numero[5,6]}/#{numero[11,4]}-#{numero[15,2]}"
  end
end
